use cfw_kit::uart::Uart;
use cfw_kit::wr_uart::UartContext;
use periph_utils::stm32f1;
use periph_utils::stm32f1::stm32f103::NVIC;
use periph_utils::stm32f1::stm32f103::{interrupt, Interrupt};
use periph_utils::GpioConfig;
use periph_utils::{DmaConfig, UartConfig, UartInit};
use proto_bytes::ice::Proto;
use utils::log;

use crate::cp_heat::HeatErr;

#[derive(GpioConfig, UartConfig)]
#[gpio(
    init = "gpio_init",
    io(name = "tx", io = "PA9", mode = "AF_PP"),
    io(name = "rx", io = "PA10", mode = "IN_FLOAT")
)]
#[uart(init = "Config", uart = 1, baud_rate = 115200)]
struct Init;
const RECV_BUF_SIZE: usize = 64;
static CTX: UartContext<64, RECV_BUF_SIZE, Init> = UartContext::uninit();

impl Uart for Init {
    fn recv_with_dma(recv_buf: &[u8]) {
        Config::usart1_rx_dma1_ch5_read(
            recv_buf.as_ptr() as _,
            USART1.dr.as_ptr() as _,
            recv_buf.len() as _,
        )
    }
    fn rx_index() -> usize {
        RECV_BUF_SIZE - Config::usart1_rx_dma1_ch5_ndtr() as usize
    }
    fn write_with_dma(write_buf: &[u8]) {
        Config::usart1_tx_dma1_ch4_write(
            write_buf.as_ptr() as _,
            USART1.dr.as_ptr() as _,
            write_buf.len() as _,
        );
    }
}

pub unsafe fn init() {
    Init::gpio_init();
    Config::dma_init();
    Config::usart1_init();
    CTX.init_once("ice_uart");
    NVIC::unmask(Interrupt::USART1);
    NVIC::unmask(Interrupt::DMA1_CHANNEL4);
}

pub fn cmd(proto: Proto) -> Result<Proto, HeatErr> {
    match CTX.write_read_until(proto, b"\r\n", 200) {
        Ok(v) => Ok(v),
        Err(e) => {
            log!("ice conn:{:?}", e);
            Err(HeatErr::IceConn)
        }
    }
}

#[interrupt]
unsafe fn USART1() {
    if Config::usart1_is_idle() {
        Config::usart1_clear_idle();
        CTX.on_idle();
    }
}

#[interrupt]
unsafe fn DMA1_CHANNEL4() {
    if Config::usart1_tx_dma1_ch4_is_tc() {
        Config::usart1_tx_dma1_ch4_clear_flags();
        CTX.on_tc();
    }
}
